package main.java.userInterface;

import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Scanner;

import main.java.regression.Regression;
import main.java.regression.RegressionUtils;
import main.java.regression.User;

public class SDAUserInterface {
	public static final String CHOICE_ONE = "1";
	public static final String CHOICE_TWO = "2";
	public static final String CHOICE_THREE = "3";
	public static final String CHOICE_FOUR = "4";
	public static final String CHOICE_FIVE = "5";
	public static final String CHOICE_ZERO = "0";
	public static final String CHOICE_Y = "y";
	public static final String CHOICE_N = "n";
	public static final String PORT_PATTERN = "\\d+";
	public static final String IPADDRESS_PATTERN = "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
			+ "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
			+ "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\."
			+ "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";

	public static void main(String[] args) {
		SDAUserInterface ui = new SDAUserInterface();
		Scanner sc = new Scanner(System.in);
		boolean exit = false;
		while (!exit) {
			ui.printInstruction();
			String cmd = sc.nextLine();
			if (cmd.equals(CHOICE_ONE)) {
				ui.doCreateRegression();
				exit = true;
			} else if (cmd.equals(CHOICE_TWO)) {
				ui.doJoinRegression();
				exit = true;
			} else if (cmd.equals(CHOICE_ZERO)) {
				exit = true;
			}
		}
		sc.close();
	}

	public void printInstruction() {
		System.out.println(UserInterfaceOutput.HEADER);
		System.out.print(UserInterfaceOutput.INSTRUCTION);
	}

	public void doCreateRegression() {
		Regression regression = new Regression();
		boolean exit = false;
		Scanner sc = new Scanner(System.in);
		doAddCreator(regression, sc);
		while (!exit) {
			System.out.print(UserInterfaceOutput.CREATE_REGRESSION_INSTRUCTION);
			String cmd = sc.nextLine();
			if (cmd.equals(CHOICE_ONE)) {
				doAddUser(regression, sc);
			}
			if (cmd.equals(CHOICE_TWO)) {
				doRemoveUser(regression, sc);
			}
			if (cmd.equals(CHOICE_THREE)) {
				doListUsers(regression);
			}
			if (cmd.equals(CHOICE_FOUR)) {
				doCreatorStartRegression(regression, sc);
			}
			if (cmd.equals(CHOICE_ZERO)) {
				exit = true;
			}
		}
		sc.close();
	}

	public void doAddCreator(Regression regression, Scanner sc) {
		while (true) {
			System.out.print(UserInterfaceOutput.ENTER_YOUR_PORT);
			String cmd = sc.nextLine();
			if (cmd.matches(PORT_PATTERN)) {
				int port = Integer.valueOf(cmd);
				User creator = new User();
				creator.setPort(port);
				String ip = "";
				try {
					ip = Inet4Address.getLocalHost().getHostAddress();
					creator.setIp(ip);
				} catch (UnknownHostException e) {
					e.printStackTrace();
				}
				creator.setConnected(true);
				regression.setCreator(creator);
				regression.setCurrentUser(creator);
				while (true) {
					System.out.print(UserInterfaceOutput.ARE_YOU_DATA_SOURCE);
					cmd = sc.nextLine();
					if (cmd.equals(CHOICE_Y)) {
						regression.addUser(creator);
						break;
					} else if (cmd.equals(CHOICE_N)) {
						break;
					}
				}
				System.out.println("Regression creator successfully added.");
				System.out.println("IPv4 address: " + ip);
				System.out.println("Port number: " + port);
				break;
			} else {
				System.out.println(UserInterfaceOutput.INVALID_PORT);
			}
		}
	}

	public void doAddUser(Regression regression, Scanner scanner) {
		User user = new User();
		System.out.println(UserInterfaceOutput.ADD_USER);
		while (true) {
			System.out.print(UserInterfaceOutput.USER_IP);
			String cmd = scanner.nextLine();
			if (cmd.matches(IPADDRESS_PATTERN)) {
				user.setIp(cmd);
				break;
			} else {
				System.out.println(UserInterfaceOutput.INVALID_IP);
			}
		}
		while (true) {
			System.out.print(UserInterfaceOutput.USER_PORT_NUMBER);
			String cmd = scanner.nextLine();
			if (cmd.matches(PORT_PATTERN)) {
				int port = Integer.valueOf(cmd);
				user.setPort(port);
				break;
			} else {
				System.out.println(UserInterfaceOutput.INVALID_PORT);
			}
		}
		regression.addUser(user);
		System.out.println(UserInterfaceOutput.USER_ADDED);
	}

	public void doListUsers(Regression regression) {
		List<User> users = regression.getDataSourceUsers();
		if (users.isEmpty()) {
			System.out.println(UserInterfaceOutput.NO_USER);
			return;
		}
		System.out.println(UserInterfaceOutput.USER_LIST);
		int i = 1;
		for (User u : users) {
			System.out.println(i + ". " + u.getIp() + ":" + u.getPort());
			i++;
		}
	}

	public void doRemoveUser(Regression regression, Scanner sc) {
		doListUsers(regression);
		List<User> list = regression.getDataSourceUsers();
		if (list.isEmpty())
			return;
		System.out.print(UserInterfaceOutput.REMOVE_USER);
		String cmd = sc.nextLine();
		if (cmd.matches(PORT_PATTERN)) {
			int choice = Integer.valueOf(cmd);
			if (1 <= choice && choice <= list.size()) {
				choice--;
				list.remove(choice);
				System.out.println(UserInterfaceOutput.USER_REMOVED);
				return;
			}
		}
		System.out.println(UserInterfaceOutput.INVALID_CHOICE);
	}

	public void doCreatorStartRegression(Regression regression, Scanner sc) {
		regression.startMessageListener();
		System.out.println(UserInterfaceOutput.LISTENER_STATRED);
		System.out.println(UserInterfaceOutput.WAITE);
		while (!RegressionUtils.checkAllUserConnected(regression)) {
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		
	}

	public void doJoinRegression() {
		Regression regression = new Regression();
		User creator = new User();
		Scanner sc = new Scanner(System.in);
		System.out.println(UserInterfaceOutput.ENTER_CREATOR_INFORMATION);
		while (true) {
			System.out.print(UserInterfaceOutput.CREATOR_IP);
			String cmd = sc.nextLine();
			if (cmd.matches(IPADDRESS_PATTERN)) {
				creator.setIp(cmd);
				break;
			} else {
				System.out.println(UserInterfaceOutput.INVALID_IP);
			}
		}
		while (true) {
			System.out.print(UserInterfaceOutput.CREATOR_PORT_NUMBER);
			String cmd = sc.nextLine();
			if (cmd.matches(PORT_PATTERN)) {
				int port = Integer.valueOf(cmd);
				creator.setPort(port);
				break;
			} else {
				System.out.println(UserInterfaceOutput.INVALID_PORT);
			}
		}
		regression.setCreator(creator);
		User user = new User();
		String ip = "";
		try {
			ip = Inet4Address.getLocalHost().getHostAddress();
			user.setIp(ip);
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
		while (true) {
			System.out.print(UserInterfaceOutput.ENTER_YOUR_PORT);
			String cmd = sc.nextLine();
			if (cmd.matches(PORT_PATTERN)) {
				int port = Integer.valueOf(cmd);
				user.setPort(port);
				break;
			} else {
				System.out.println(UserInterfaceOutput.INVALID_PORT);
			}
		}
		user.setConnected(true);
		regression.setCurrentUser(user);
		regression.addUser(user);
		doJoinerStartRegression(regression, sc);
		sc.close();
	}

	public void doJoinerStartRegression(Regression regression, Scanner sc) {
		regression.startMessageListener();
		System.out.println(UserInterfaceOutput.LISTENER_STATRED);
		regression.pingUser(regression.getCreator());
		System.out.println(UserInterfaceOutput.WAITE);
		while (!RegressionUtils.checkAllUserConnected(regression)) {
			try {
				Thread.sleep(5000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
